package com.monkey.luffer.springboot.demo.basis.kcc.s3cmd;

import com.amazonaws.services.s3.AmazonS3;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author jiahong.liu
 */
public class AnalysisDatascript implements S3Oper {
    private static final String CONTENT =
            "预期时间：\\n" +
            "\\n" +
            "\\n" +
            "数据库地址：" +
            "\\n" +
            "{db-address}" +
            "\\n" +
            "\\n" +
            "执行步骤：" +
            "\\n" +
            "1.下载附件：{zip}.zip,并解压" +
            "\\n" +
            "2.登录{db-cluster},执行：\\n" +
            "cd {zip}\\n" +
            "source ./runall.sql\\n\\n" +
            "rollback步骤：\\n" +
            "{rollback}";


    private boolean hasRollBack = false;
    private static Map<String, Map<String, String>> envMap;

    static {
        envMap = new HashMap<>();
        Map<String, String> staging = new HashMap<>();
        Map<String, String> live = new HashMap<>();
        envMap.put("staging", staging);
        envMap.put("live", live);
        staging.put("ibank-00", "ibank-master-00-staging.db.maribanksvc.com:6606");
        staging.put("corebank-00", "corebank-master-00-staging.db.maribanksvc.com:6606");
        staging.put("corebank-01", "corebank-master-00-staging.db.maribanksvc.com:6606");
        staging.put("corebank-02", "corebank-master-00-staging.db.maribanksvc.com:6606");

        live.put("ibank-00", "ibank-master-00.db.maribanksvc.com:6606");
        live.put("corebank-00", "corebank-master-00.db.maribanksvc.com:6606");
        live.put("corebank-01", "corebank-master-01.db.maribanksvc.com:6606");
        live.put("corebank-02", "corebank-master-02.db.maribanksvc.com:6606");
    }

    @Override
    public void request(AmazonS3 s3, MyCmd cmd) {
        List<String> destFile = new ArrayList<>();
        String srcPath = cmd.getSrcPath().endsWith("/") ? cmd.getSrcPath().substring(0,  cmd.getSrcPath().length() - 1) : cmd.getSrcPath();
        String version = cmd.getVersion();
        String destPath = cmd.getDstPath();
        String env = cmd.getEnv();
        boolean gitFlag = cmd.getGitFlag();
        String wholePath = srcPath + "/"  + version;
        boolean ticketFlag = cmd.getTicketFlag();
        File srcFile = new File(wholePath);
        File[] fileArray = srcFile.listFiles();
        if (fileArray == null || fileArray.length == 0) {
            System.out.println("目标文件下不存在目录");
            return;
        }

        File dest = new File(destPath);
        if (!dest.exists()) {
            dest.mkdirs();
        }

        // 先切到dev分支，再拉一下最新分支
        try {
            if (gitFlag) {
                for (File file: fileArray) {
                    if (file.isDirectory()) {
                        File initFile = new File(file.getAbsolutePath() + "/" + "init");
                        String name = file.getName();
                        if (initFile.exists()) {
                            File[] newFileArray = initFile.listFiles();
                            if (newFileArray != null) {
                                for (File newFile: newFileArray) {
                                    if (file.isDirectory()) {
                                        switch (newFile.getName()) {
                                            case "DDL" :
                                                operateDdl(newFile, destPath, version, destFile, name);
                                                break;
                                            case "DML":
                                                operateDml(newFile, destPath, version, destFile, name);
                                                break;
                                            default:
                                                break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            destFile.clear();
            File[] destFiles = dest.listFiles();
            assert destFiles != null;
            for (File tmp: destFiles) {
                if (tmp.isDirectory() && (tmp.getName().contains("DDL") || tmp.getName().contains("DML"))) {
                    destFile.add(tmp.getAbsolutePath());
                }
            }

            readFile(destFile, env, ticketFlag);
            Thread.sleep(10000);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("exception happened..." + e);
        }
    }



    private void readFile(List<String> destFile, String env, boolean ticketFlag) throws IOException {
        for (String path: destFile) {
            List<String> tables = new ArrayList<>();
            Map<String,String> map = new HashMap<>();
            File file = new File(path);
            readFile(file, tables);
            map.put("name", env + " " + new File(path).getName());
            path = path + ".txt";
            String content = CONTENT;
            if (hasRollBack) {
                content = content.replace("{rollback}", "cd {zip}/rollback\\n source ./rollback_runall.sql");
            } else {
                content = content.replace("{rollback}", "该语句不需要rollback");
            }

            if (path.contains("ibank-00")) {
                content = content.replace("{db-address}", envMap.get(env).get("ibank-00"));
                content = content.replace("{db-cluster}", "ibank-00");
                map.put("db-address", envMap.get(env).get("ibank-00"));
                map.put("db-cluster", "ibank-00");
            }

            if (path.contains("corebank-01")) {
                content = content.replace("{db-address}", envMap.get(env).get("corebank-01"));
                content = content.replace("{db-cluster}", "corebank-01");
                map.put("db-address", envMap.get(env).get("corebank-01"));
                map.put("db-cluster", "corebank-01");
            }

            if (path.contains("corebank-02") || path.contains("admin-portal")) {
                content = content.replace("{db-address}", envMap.get(env).get("corebank-02"));
                content = content.replace("{db-cluster}", "corebank-02");
                map.put("db-address", envMap.get(env).get("corebank-02"));
                map.put("db-cluster", "corebank-02");
            }

            if (path.contains("corebank-00")) {
                content = content.replace("{db-address}", envMap.get(env).get("corebank-00"));
                content = content.replace("{db-cluster}", "corebank-00");
                map.put("db-address", envMap.get(env).get("corebank-00"));
                map.put("db-cluster", "corebank-00");
            }

            if (path.contains("DDL")) {
                map.put("sql", "DDL");
            }

            if (path.contains("DML")) {
                map.put("sql", "DML");
            }

            content = content.replace("{zip}" ,file.getName());
            String tableNames = tables.toString().replaceAll("`", "");
            content = content.replace("{tableNames}", tableNames);
            map.put("content", content);
            map.put("tableNames", tableNames);
            hasRollBack = false;
            writeFile(new File(path), content);
            if (ticketFlag) {
                new Thread(()-> {
                    try {
                        new CreateTicket().createTicket(env, map);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }).start();
            }
        }
    }

    private void readFile (File file, List<String> tables) throws IOException {
        if (file.isFile()) {
            readFileByLine(file, tables);
        }

        File[] fileArr = file.listFiles();
        if (fileArr == null || fileArr.length == 0) {
            return;
        }

        for (File subFile: fileArr) {
            if (file.isDirectory()) {
                if (file.getName().contains("rollback")) {
                    hasRollBack = true;
                }
                readFile(subFile, tables);
            } else {
                readFileByLine(subFile, tables);
            }
        }
    }

    private void readFileByLine(File file, List<String> tables) throws IOException {
        FileInputStream inputStream = new FileInputStream(file);
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String schema = "";
        String str;
        while((str = bufferedReader.readLine()) != null)
        {
            str = str.toUpperCase().trim();
            if (str.contains("USE ")) {
                String[] strArr = str.split(" ");
                String table = strArr[1];
                if (table.endsWith(";")) {
                    schema = table.substring(0, table.length() -1);
                }
            }
            str = str.replace("IF NOT EXISTS", "");
            str = str.replace("IF EXISTS", "");
            String table = "";
            if (str.contains("CREATE ") || str.contains("ALTER ") || str.contains("DROP ")) {
                table = createDropAndAlter(str, schema);
            }

            if (str.contains("UPDATE ")) {
                table = updateSql(str, schema);
            }

            if(str.contains("INSERT INTO ") || str.contains("DELETE FROM ")) {
                table = createDropAndAlter(str, schema);
            }

            if (!StringUtils.isEmpty(table) && !tables.contains(table)) {
                if (table.endsWith("(")) {
                    table = table.substring(0, table.length() - 1);
                }
                table = table.trim();
                tables.add(table);
            }
        }
    }

    private String updateSql(String str, String schema) {
        String[] strArr = str.split(" ");
        if (strArr.length < 2) {
            return "";
        }

        String table = strArr[1];
        if (table.endsWith(";")) {
            table = table.substring(0, table.length() -1);
        }

        if (!StringUtils.isEmpty(schema)) {
            table = schema.trim() + "." + table;
        }
        return table;
    }

    private String createDropAndAlter(String str, String schema) {
        String[] strArr = str.split(" ");
        if (strArr.length < 3) {
            return "";
        }

        String table = strArr[2];
        if (table.endsWith(";")) {
            table = table.substring(0, table.length() -1);
        }

        if (!StringUtils.isEmpty(schema)) {
            table = schema.trim() + "." + table;
        }
        return table;
    }

    private void writeFile(File file, String content) {
        try {
            if(!file.exists()){
                boolean flag = file.createNewFile();
                if (!flag) {
                    System.out.println("Create file failed, please check");
                    return;
                }
            }
            FileWriter fileWriter = new FileWriter(file);
            BufferedWriter bufferWriter = new BufferedWriter(fileWriter);
            bufferWriter.write(content);
            bufferWriter.close();
            System.out.println("Write file done");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void operateDdl(File file, String destPath, String version, List<String> destFile, String name) throws IOException {
        // rollback目录：
        String rollback = file.getAbsolutePath().replace("/init/DDL", "/rollback/DDL");

        String filePath = file.getAbsolutePath();
        String tmpDestPath = destPath + "/" + version + "_" + name + "_DDL";
        destFile.add(tmpDestPath);
        copyDir(filePath, tmpDestPath);
        String rollbackFilePath = destPath + "/rollback";
        String sourceRollBack = rollback + "/" + name;
        copyDir(sourceRollBack, rollbackFilePath);

    }

    private void operateDml(File file, String destPath, String version, List<String> destFile, String name) throws IOException {
        // rollback目录：
        String rollback = file.getAbsolutePath().replace("/init/DML", "/rollback/DML");
        String filePath = file.getAbsolutePath();
        String tmpDestPath = destPath + "/" + version  + "_" + name + "_DML";
        destFile.add(tmpDestPath);
        copyDir(filePath, tmpDestPath);
        String rollbackFilePath = tmpDestPath + "/rollback";
        String sourceRollBack = rollback + "/" + name;
        copyDir(sourceRollBack, rollbackFilePath);

    }


    public static void copyDir(String sourcePath, String newPath) throws IOException {
        File start = new File(sourcePath);
        if (!start.exists()) {
            return;
        }
        File end = new File(newPath);
        String[] filePath = start.list();
        if(!end.exists()) {
            end.mkdir();
        }

        assert filePath != null;
        for(String temp: filePath) {
            //查看其数组中每一个是文件还是文件夹
            if(new File(sourcePath + File.separator + temp).isDirectory()) {
                //为文件夹，进行递归
                copyDir(sourcePath + File.separator + temp, newPath + File.separator + temp);
            }else {
                //为文件则进行拷贝
                copyFile(sourcePath + File.separator + temp, newPath + File.separator + temp);
            }
        }
    }

    public static void copyFile(String sourcePath, String newPath) throws IOException {
        File start = new File(sourcePath);
        File end = new File(newPath);
        if (!end.exists()) {
            end.createNewFile();
        }
        try(BufferedInputStream bis=new BufferedInputStream(new FileInputStream(start));
            BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(end))) {
            int len;
            byte[] flush = new byte[1024];
            while((len=bis.read(flush)) != -1) {
                bos.write(flush, 0, len);
            }
            bos.flush();
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
}
